#pragma once

#include "XiInclude.hpp"

XI_NAMESPACE_BEGIN

class XiCharStream
{
public:
	struct Location
	{
		XiUInt32 m_line;
		XiUInt32 m_column;
	};

	enum { InvalidChar = static_cast<XiChar>(-1) };
public:
	XiCharStream(void)
	{
		m_endOfStream = false;
		m_currentLocation.m_line = 1;
		m_currentLocation.m_column = 1;
		m_cachedChar = InvalidChar;
	}

	XiChar NextChar(Location *location = NULL)
	{
		if (location != NULL)
			*location = m_currentLocation;

		if (m_endOfStream)
			return 0;

		XiUInt32 nextChar;
		if (m_cachedChar != InvalidChar)
		{
			nextChar = m_cachedChar;
			m_cachedChar = InvalidChar;
		}
		else
			nextChar = GetChar();

		if (nextChar == 0)
			m_endOfStream = true;
		else if (nextChar == L'\r')
		{
			XiUInt32 theCharAfterNext = GetChar();
			if (theCharAfterNext == L'\n')
				nextChar = theCharAfterNext;
			else
				m_cachedChar = theCharAfterNext;

			m_currentLocation.m_line++;
			m_currentLocation.m_column = 1;
		}
		else
			m_currentLocation.m_column++;

		return nextChar;
	}
protected:
	virtual XiChar GetChar(void) = 0;
private:
	bool m_endOfStream;
	Location m_currentLocation;
	XiChar m_cachedChar;
};

class XiStringStream : public XiCharStream
{
public:
	XiStringStream(const XiString &text)
	{
		m_iter = text.begin();
		m_iterEnd = text.end();
	}
protected:
	virtual XiChar GetChar(void)
	{
		if (m_iter != m_iterEnd)
			return *m_iter++;
		else
			return 0;
	}
private:
	XiString::const_iterator m_iter, m_iterEnd;
};

XI_NAMESPACE_END